home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / MAILLIB.C < prev    next >
C/C++ Source or Header  |  1991-12-06  |  17KB  |  552 lines

  1. /*
  2.       maillib.c
  3.  
  4.       mail user agent subroutine library for UUPC/extended
  5.  
  6.       Changes copyright 1990, Andrew H. Derbyshire
  7.  
  8.       Change History:
  9.  
  10.          3 May 90 Create from mail.c
  11.  *       16 Jun 90:  Added support for mail (~) subcommands          pdm
  12.  *                   chgd calling seq of Collect_Mail to support above
  13.  *                   chges to CopyMsg to support ~i subcmd
  14.  *                   mods to SendMail to support autosign option
  15.  *                   broke out signature append code to seperate fn
  16.  *                   added support for alternate signature file
  17.  */
  18.  
  19. #include <ctype.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include "lib.h"
  25. #include "address.h"
  26. #include "hlib.h"
  27. #include "mlib.h"
  28. #include "alias.h"
  29. #include "mail.h"
  30. #include "maillib.h"
  31.  
  32. #define  PAGESIZE 23
  33. #define  INDENT "> "
  34.  
  35. /*--------------------------------------------------------------------*/
  36. /*       Local variables                                              */
  37. /*--------------------------------------------------------------------*/
  38.  
  39. static int PageCount = 0;
  40.  
  41. static char *ignorelist[] =  { "Message-ID:",
  42.                         "Received:",
  43.                         "Status: ",
  44.                         "X-Mailer: ",
  45.                         "From " ,
  46.                         "" };
  47.  
  48. currentfile();                /* Define current file for panic()     */
  49.  
  50. /*------------------------------------------------------------------*/
  51. /*    P a g e r                                                     */
  52. /*                                                                  */
  53. /*    Page through a message                                        */
  54. /*                                                                  */
  55. /* There are hooks here to let the user use his/her own pager, like */
  56. /* LIST, MORE, or LESS.  We just write the message out to a         */
  57. /* temporary file and invoke the appropriate external program to do */
  58. /* the browsing.                                                    */
  59. /*------------------------------------------------------------------*/
  60.  
  61. boolean Pager(const int msgnum,
  62.               boolean external,
  63.               copyopt received,
  64.               const boolean reset)
  65. {
  66.    long nextloc;
  67.    char *browse   = NULL;
  68.    char buf[BUFSIZ];
  69.    boolean exit  = FALSE;        /* Flag for PRE-MATURE exit   ahd   */
  70.    FILE *fmailbag;
  71.  
  72.    if (msgnum == -1)
  73.       return FALSE;
  74.  
  75.    if (bflag[F_PAGER])           /* User want pager option inverted? */
  76.       external = ! external;     /* Yes --> Do the inversion         */
  77.  
  78.    if (letters[msgnum].status < M_READ)
  79.       letters[msgnum].status = M_READ;
  80.  
  81.    if (external && (E_pager != nil(char)))
  82.    {
  83.       browse = mktempname( NULL,"TMP" );/* Get a temporary file name */
  84.  
  85.       if ((fmailbag = FOPEN(browse, "w", TEXT)) == nil(FILE))
  86.       {
  87.          printerr(browse);
  88.          printmsg(0,"Cannot open browse file %s",browse);
  89.          return FALSE;
  90.       } /* if */
  91.       CopyMsg(msgnum, fmailbag, received, FALSE);
  92.       fclose(fmailbag);
  93.  
  94.       L_invoke_pager(E_pager, browse);
  95.       remove(browse);
  96.       free(browse);
  97.  
  98.    } /* if */
  99.    else {
  100.       fseek(fmailbox, letters[msgnum].adr , SEEK_SET);
  101.       nextloc = letters[msgnum + 1].adr;
  102.  
  103.       if ( reset )
  104.          ClearScreen();
  105.       else
  106.          PageLine("\n");
  107.  
  108.       sprintf(buf,"Mailbox item %d:\n",msgnum + 1);
  109.       PageLine(buf);
  110.       while (ftell(fmailbox) < nextloc && (!exit) &&
  111.          fgets(buf, BUFSIZ, fmailbox) != nil(char))
  112.       {
  113.          boolean print = TRUE;
  114.  
  115.          switch(received)
  116.          {
  117.             case nocontinue:
  118.                if ((*buf != '\n') && !isgraph(*buf)) {
  119.                   print = FALSE;
  120.                   break;
  121.                }
  122.                else
  123.                   received = noreceived;
  124.             case noreceived:
  125.             {
  126.                char entry = 0;
  127.                while ( strlen(ignorelist[entry]) && print )
  128.                {
  129.                   if (equalni(ignorelist[entry],
  130.                         buf,strlen(ignorelist[entry])))
  131.                   {
  132.                      print = FALSE;
  133.                      received = nocontinue;
  134.                   }
  135.                   else
  136.                      entry++;
  137.                } /* while */
  138.             } /* case noreceived */
  139.          } /* switch */
  140.          if (received != seperators)
  141.             if (equal(buf,"\n"))
  142.                received = seperators;
  143.  
  144.          if (print)
  145.             if (PageLine(buf))         /* Exit if the user hits Q    */
  146.                exit = TRUE;
  147.       } /* while */
  148.  
  149.       if (equal(buf,"\n") && (!exit))                 /* ahd   */
  150.          putchar('\n');                               /* ahd   */
  151.    } /* else */
  152.  
  153.    return ! exit;
  154. } /*Pager*/
  155.  
  156.  
  157. /*
  158.       S u b _ P a g e r
  159.          pager for the ~p mail subcommand
  160.          page through a mail message currently being entered
  161.  
  162.       Clone of the Pager function
  163.  
  164.  */
  165.  
  166. void Sub_Pager(const char *tinput,
  167.                      boolean external )
  168. {
  169.    boolean exit  = FALSE;        /* Flag for PRE-MATURE exit   ahd   */
  170.  
  171.    if (bflag[ F_PAGER ])
  172.       external = ! external;
  173.  
  174.    if ( external && (E_pager != nil(char)) )
  175.       L_invoke_pager(E_pager, tinput);
  176.    else {
  177.       FILE *finput;
  178.       char buf[BUFSIZ];
  179.       finput = FOPEN(tinput, "r", TEXT);
  180.       if (finput == NULL) {
  181.          printmsg(0,"Cannot open file %s for display",tinput);
  182.          printerr(tinput);
  183.          return;
  184.       }
  185.       PageReset();
  186.       ClearScreen();
  187.       while ( (!exit) && fgets(buf, BUFSIZ, finput) != nil(char))
  188.       {
  189.         if (PageLine(buf))         /* Exit if the user hits Q  */
  190.            exit = TRUE;
  191.       }
  192.       fclose(finput);
  193.    }
  194.  
  195. } /*Sub_Pager*/
  196.  
  197. /*
  198.       P a g e R e s e t
  199.  
  200.       Reset page function to top of page
  201.  */
  202.  
  203. void PageReset()
  204. {
  205.    PageCount = 0;
  206. } /*PageReset*/
  207.  
  208. /*
  209.       P a g e L i n e
  210.  
  211.       Print one line when paging through a file
  212.  */
  213.  
  214. boolean PageLine(char *line)
  215. {
  216.  
  217.    fputs(line, stdout);
  218.  
  219.    PageCount = PageCount + 1 + strlen(line) / 81; /* Handle long lines  */
  220.  
  221.    if (PageCount > PAGESIZE) {
  222.       int c;
  223.       PageCount = 0;
  224.       fputs("More?", stdout);
  225.       c = Get_One();
  226.       switch (tolower(c)) {
  227.       case 'q':
  228.       case '\003':
  229.       case 'n':                     /* Because that's what I keep Pressing */
  230.       case 'x':
  231.          puts("\rAborted.\n");
  232.          return TRUE;
  233.  
  234.       case 'd':
  235.          PageCount = PAGESIZE / 2;        /* Half a Page More */
  236.          break;
  237.       case '\r':                                                  /* ahd   */
  238.          PageCount = PAGESIZE;        /* Only print one line  */  /* ahd   */
  239.       }
  240.       fputs("\r      \r",stdout);
  241.    }
  242.  
  243.    return FALSE;
  244.  
  245. } /*PageLine*/
  246.  
  247.  
  248. /*
  249.    C o p y M s g
  250.  
  251.    Copy a message
  252.  
  253.    Allows copying message with one or more of the options specified
  254.    in the copyopt data type.
  255. */
  256.                                                 /* added indent arg  pdm */
  257. boolean CopyMsg(int msgnum, FILE *f, copyopt headers, boolean indent)
  258. {
  259.    long nextloc;
  260.    boolean print;
  261.    char buf[BUFSIZ];
  262.  
  263. /*--------------------------------------------------------------------*/
  264. /*                 Write a separator line, if needed                  */
  265. /*--------------------------------------------------------------------*/
  266.  
  267.    if (headers == seperators)
  268.    {
  269.       if (fputs(MESSAGESEP,f) == EOF)     /* Write out separator line   */
  270.       {
  271.          printerr("CopyMsg");
  272.          panic();
  273.       } /* if (fputs(MESSAGESEP,f) == EOF) */
  274.    } /* if (headers == seperators) */
  275.  
  276. /*--------------------------------------------------------------------*/
  277. /*             else add a one line from line, if desired              */
  278. /*--------------------------------------------------------------------*/
  279.  
  280.    else if (headers == fromheader )
  281.    {
  282.       register char *sp = buf;
  283.       headers = noheader;                 /* Do not print full header       */
  284.       if (RetrieveLine(letters[msgnum].date, buf, LSIZE))
  285.       {
  286.          register char  *sp = buf;
  287.          while (!isspace(*sp))
  288.             sp++;
  289.          while (isspace(*sp))
  290.             sp++;
  291.          fprintf(f,"On %s,", sp );
  292.       } /* if */
  293.  
  294.       if (RetrieveLine(letters[msgnum].from, buf, BUFSIZ))
  295.       {
  296.          while (!isspace(*sp) && (*sp != '\0'))
  297.             sp++;
  298.          BuildAddress( buf, sp );
  299.       } /* if */
  300.       else
  301.          strcpy(buf,"you");   /* Wimp out without admitting it       */
  302.  
  303.       fprintf(f, " %s wrote:\n", buf) ;
  304.    } /* if (headers == fromheader ) */
  305.  
  306. /*--------------------------------------------------------------------*/
  307. /*              Now position to the front of the letter               */
  308. /*--------------------------------------------------------------------*/
  309.  
  310.    fseek(fmailbox, letters[msgnum].adr , SEEK_SET);
  311.    nextloc = letters[msgnum + 1].adr;
  312.  
  313.    while (ftell(fmailbox) < nextloc &&
  314.       fgets(buf, BUFSIZ, fmailbox) != nil(char)) {
  315.  
  316. /*--------------------------------------------------------------------*/
  317. /*               Determine if we should write the line                */
  318. /*--------------------------------------------------------------------*/
  319.  
  320.       print = TRUE;
  321.  
  322.       switch (headers)
  323.       {
  324.          case noheader:
  325.             print = FALSE;
  326.             break;
  327.  
  328.          case nocontinue:
  329.             if ((*buf != '\n') && !isgraph(*buf)) {
  330.                print = FALSE;
  331.                break;
  332.             }
  333.             else
  334.                headers = noreceived;
  335.                /* Fall through ... */
  336.          case noreceived:
  337.          {
  338.             char entry = 0;
  339.             while ( strlen(ignorelist[entry]) && print )
  340.             {
  341.                if (equalni(ignorelist[entry],buf,strlen(ignorelist[entry])))
  342.                {
  343.                   print = FALSE;
  344.                   headers = nocontinue;
  345.                }
  346.                else
  347.                   entry++;
  348.             }
  349.          } /* case noreceived */
  350.                /* Fall through */
  351.          case noseperator:
  352.          case seperators:
  353.             break;
  354.  
  355.          default:
  356.             printmsg(0,"CopyMsg: Bad header copy state of %d",headers);
  357.             panic();
  358.       } /* switch */
  359.  
  360. /*--------------------------------------------------------------------*/
  361. /*                 If we should print the line, do so                 */
  362. /*--------------------------------------------------------------------*/
  363.  
  364.       if (print)
  365.       {
  366.          if (indent)
  367.          {
  368.             if ( fputs(INDENT , f ) == EOF )
  369.             {
  370.                printerr( "CopyMsg" );
  371.                panic();
  372.             } /* if ( fputs(INDENT , f ) == EOF ) */
  373.          } /* if (indent) */
  374.  
  375.          if ( fputs(buf , f ) == EOF )
  376.          {
  377.             printerr( "CopyMsg" );
  378.             panic();
  379.          } /* if ( fputs(buf , f ) == EOF ) */
  380.  
  381.       } /* if (print) */
  382.  
  383. /*--------------------------------------------------------------------*/
  384. /*  If end of the header, print all data until the end of the input   */
  385. /*--------------------------------------------------------------------*/
  386.  
  387.       if ( (headers != seperators) && equal(buf, "\n") )
  388.          headers = seperators;
  389.  
  390.    } /*while*/
  391.  
  392.    return TRUE;
  393. } /*CopyMsg*/
  394.  
  395. /*--------------------------------------------------------------------*/
  396. /*    N u m e r i c                                                   */
  397. /*                                                                    */
  398. /*    Determine if a string is numeric.  Returns TRUE if string is    */
  399. /*    numeric, else FALSE.                                            */
  400. /*--------------------------------------------------------------------*/
  401.  
  402.  boolean Numeric( const char *number)
  403.  {
  404.    char *column = (char *) number;
  405.  
  406.    if (*column == '\0')
  407.       return FALSE;
  408.  
  409.    while( isdigit(*column) )  /* Scan to string end or 1st non-digit */
  410.       column++;
  411.  
  412.    return *column == '\0';    /* Success if whole string was made of
  413.                                  digits                              */
  414.  } /* Numeric */
  415.  
  416. /*--------------------------------------------------------------------*/
  417. /*    R e t r i e v e L i n e                                         */
  418. /*                                                                    */
  419. /*    Read a line from a mail header, if available                    */
  420. /*--------------------------------------------------------------------*/
  421.  
  422. boolean RetrieveLine(long adr, char *line, const size_t len)
  423. {
  424.    char *cp = line;
  425.    size_t count;
  426.  
  427.    *line = '\0';              /* Insure nothing to find              */
  428.    if (adr == MISSING)        /* No information to read?             */
  429.       return FALSE;           /* Report this to caller               */
  430.  
  431.    if (fseek(fmailbox, adr, SEEK_SET)) /* Position to data           */
  432.    {                          /* Have a problem?                     */
  433.       printerr("mailbox");    /* Yes --> Report and return           */
  434.       return FALSE;
  435.    }
  436.  
  437. /*--------------------------------------------------------------------*/
  438. /*                     Actually read the data in                      */
  439. /*--------------------------------------------------------------------*/
  440.  
  441.    count = fread(line, sizeof *line, len-1, fmailbox);
  442.  
  443.    if ((count < (len-1)) && ferror( fmailbox ))
  444.    {
  445.       printerr( "RetrieveLine");
  446.       return FALSE;
  447.    }
  448.  
  449.    line[count] = '\0';        /* Terminate the string read           */
  450.  
  451. /*--------------------------------------------------------------------*/
  452. /*    A field continues until a new field begins in column of the     */
  453. /*    next line or the header ends (an empty line); find the end      */
  454. /*    of the field, trimming extra white space from the beginning     */
  455. /*    of each line as we go                                           */
  456. /*--------------------------------------------------------------------*/
  457.  
  458.    while( (cp = strchr(cp , '\n')) != NULL )
  459.    {
  460.       if ((cp[1] == '\n') || !isspace(cp[1]))   /* End of field?     */
  461.          *cp = '\0';          /* Yes --> Terminate string            */
  462.       else {
  463.          char *next;
  464.  
  465.          *cp++ = ' ';         /* Convert line break to whitespace    */
  466.          next = ++cp;         /* Get first position of new line      */
  467.          while( isspace( *next ) )  /* Ignore leading white space    */
  468.             next++;
  469.  
  470.          memmove( cp , next , strlen(next) + 1 );
  471.                               /* Trim leading white space            */
  472.       } /* else */
  473.    } /* while */
  474.  
  475.    return TRUE;
  476.  
  477. } /*RetrieveLine*/
  478.  
  479. /*--------------------------------------------------------------------*/
  480. /*    R e t u r n A d d r e s s                                       */
  481. /*                                                                    */
  482. /*    Returns the user name (if available and requested or            */
  483. /*    E-mail address of the user                                      */
  484. /*                                                                    */
  485. /*    Written by ahd 15 July 1989                                     */
  486. /*--------------------------------------------------------------------*/
  487.  
  488. void ReturnAddress(char *line, struct ldesc *ld)
  489. {
  490.    char buffer[BUFSIZ];
  491.  
  492.    if (!RetrieveLine(ld->from, buffer, BUFSIZ))
  493.                                           /* From: line available?   */
  494.       strcpy(line,"-- Unknown --");       /* No --> Return error     */
  495.    else {
  496.       char *begin = buffer;
  497.       while (!isspace(*begin) && (*begin != '\0'))
  498.          begin++;
  499.       if (strlen(begin))
  500.          ExtractName(line,begin);         /* Yes --> Return name     */
  501.       else
  502.          strcpy(line,"-- Invalid From: line --");
  503.    }
  504.  
  505.    return;
  506.  
  507. } /*ReturnAddress*/
  508.  
  509. /*--------------------------------------------------------------------*/
  510. /*    s a y o p t i o n s                                             */
  511. /*                                                                    */
  512. /*    Announce user options in effect                                 */
  513. /*--------------------------------------------------------------------*/
  514.  
  515. void sayoptions( FLAGTABLE *flags)
  516. {
  517.  
  518.    size_t subscript;
  519.    size_t used = 0;
  520.  
  521.    printf("\nThe following options are set:\n");
  522.  
  523.    for (subscript = 0; (subscript < F_LAST); subscript++)
  524.    {
  525.          size_t width;
  526.  
  527.          if (flags[subscript].bits & B_GLOBAL)
  528.             continue;               /* Don't print system options */
  529.  
  530.          width = 1 + strlen( flags[subscript].sym ) +
  531.                  ( bflag[ flags[subscript].position ] ? 0 : 2 );
  532.  
  533.          used += width;
  534.          if ( subscript > 0 )
  535.          {
  536.             if ( used > 79 )
  537.             {
  538.                putchar('\n');
  539.                used = width;
  540.             } /* if ( used > 79 ) */
  541.             else
  542.                putchar(' ');
  543.          } /* if ( subscript > 0 ) */
  544.  
  545.          printf("%s%s",
  546.             bflag[ flags[subscript].position ] ? "" : "no" ,
  547.             flags[subscript].sym );
  548.  
  549.    } /* for */
  550.    putchar('\n');
  551. } /* sayoptions */
  552.